/*
*    TG_Code : Dzlua
*    Email   : 505544956@qq.com
*    Time    : 2017/07/28
*/
#include "TangoPackage.h"

namespace tg {

namespace {
    Package::eAction tg_pkg_ts_action(const uint8_t &act) {
        Package::eAction eact = Package::eAction::unknown;
        switch (act) {
            case 1: eact = Package::eAction::request; break;
            case 2: eact = Package::eAction::header; break;
            case 3: eact = Package::eAction::dis_conn; break;
            case 4: eact = Package::eAction::dis_conn_client; break;
            case 5: eact = Package::eAction::had_data; break;
            default : eact = Package::eAction::unknown; break;
        }
        return eact;
    }

    uint8_t tg_pkg_ts_action(const Package::eAction &eact) {
        uint8_t act = 0;
        switch (eact) {
            case Package::eAction::request: act = 1; break;
            case Package::eAction::header: act = 2; break;
            case Package::eAction::dis_conn: act = 3; break;
            case Package::eAction::dis_conn_client: act = 4; break;
            case Package::eAction::had_data: act = 5; break;
            default : act = 0; break;
        }
        return act;
    }
} // end namespace

PackageRead::PackageRead(const char *buffer, size_t len)
        : buffer_(nullptr)
        , len_(0) {
    if (!buffer || len <= 0)
        return;
    
    buffer_ = new char[len];
    if (!buffer_) return;
    
    memcpy(buffer_, buffer, len);
    len_ = len;
}

PackageRead::~PackageRead() {
    len_ = 0;
    if (buffer_) {
        delete[] buffer_;
        buffer_ = nullptr;
    }
}

bool PackageRead::IsOK() {
    if (!buffer_) return false;

    if ( this->GetLength() + sizeof(uint16_t)
            != len_ ) {
        return false;
    }

    if (sizeof(uint16_t) 
            + sizeof(uint8_t)
            + sizeof(SOCKET) * 2
            + sizeof(uint16_t)
            + this->GetDataLength()
            != len_) {
        return false;
    }

    if (Package::eAction::unknown
            == this->GetAction() ) {
        return false;
    }

    return true;
}

uint16_t PackageRead::GetLength() {
    uint16_t len_pkg = 0;
    memcpy(&len_pkg, buffer_, sizeof(uint16_t));
    return len_pkg;
}

Package::eAction PackageRead::GetAction() {
    uint8_t act = 0;
    memcpy(&act, buffer_ + sizeof(uint16_t), sizeof(uint8_t));
    return tg_pkg_ts_action(act);
}

SOCKET PackageRead::GetLocalSocket() {
    SOCKET sock = 0;
    memcpy(&sock, buffer_ + sizeof(uint16_t) + sizeof(uint8_t), sizeof(SOCKET));
    return sock;
}

SOCKET PackageRead::GetRemoteSocket() {
    SOCKET sock = 0;
    memcpy(&sock, buffer_ + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(SOCKET), sizeof(SOCKET));
    return sock;
}

uint16_t PackageRead::GetDataLength() {
    uint16_t len = 0;
    memcpy(&len, buffer_ + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(SOCKET) * 2, sizeof(uint16_t));
    return len;
}

const char* PackageRead::GetDataBuffer() {
    return ( buffer_ + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(SOCKET) * 2 + sizeof(uint16_t) );
}

sockaddr_in PackageRead::GetRemoteAddr() {
    sockaddr_in addr = { 0 };
    if (Package::eAction::request
            != this->GetAction() ) {
        return addr;
    }

    memcpy(&addr, buffer_ + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(SOCKET) * 2 + sizeof(uint16_t), sizeof(sockaddr_in));
    return addr;
}

void PackageRead::SetRemoteAddr(sockaddr_in &addr) {
    if (Package::eAction::request
            != this->GetAction() ) {
        return;
    }

    memcpy(buffer_ + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(SOCKET) * 2 + sizeof(uint16_t), &addr, sizeof(sockaddr_in));
}

uint16_t PackageRead::GetRequestDataLength() {
    return this->GetDataLength() - sizeof(sockaddr_in);
}

const char* PackageRead::GetRequestDataBuffer() {
    return this->GetDataBuffer() + sizeof(sockaddr_in);
}

//-------------------------//
PackageWrite::PackageWrite() {
    this->Reset();
}

PackageWrite::~PackageWrite() {
    this->Reset();
}
//-------------------------//
void PackageWrite::CalculateBufferSize() {
    buf_len_ = sizeof(uint16_t) + sizeof(uint8_t) + sizeof(SOCKET) * 2 + sizeof(uint16_t) + data_len_;
}
//-------------------------//
void PackageWrite::Commit() {
    this->CalculateBufferSize();
    buffer_ = new char[buf_len_];

    char *p = buffer_;
    uint16_t templen = buf_len_ - sizeof(uint16_t);
    // all len
    memcpy(p, &templen, sizeof(uint16_t));
    p += sizeof(uint16_t);
    // action
    uint8_t act = tg_pkg_ts_action(action_);
    memcpy(p, &act, sizeof(uint8_t));
    p += sizeof(uint8_t);
    // local sock
    memcpy(p, &sock_local_, sizeof(SOCKET));
    p += sizeof(SOCKET);
    // remote sock
    memcpy(p, &sock_remote_, sizeof(SOCKET));
    p += sizeof(SOCKET);
    // data len
    memcpy(p, &data_len_, sizeof(uint16_t));
    p += sizeof(uint16_t);
    //
    if (data_len_ <= 0) return;

    // data buf
    memcpy(p, data_buf_, data_len_);
    p += data_len_;

}

const char* PackageWrite::GetDataBuffer() {
    return buffer_;
}

uint16_t PackageWrite::GetDataLength() {
    return buf_len_;
}

void PackageWrite::Reset() {
    action_ = Package::eAction::unknown;
    sock_local_ = 0;
    sock_remote_ = 0;
    data_len_ = 0;
    data_buf_ = 0;

    if (buffer_) {
        delete[] buffer_;
        buffer_ = nullptr;
    }
    buf_len_ = 0;
}

#ifdef DEBUG
void PackageWrite::Dump() {
    printf("--------- PackageWrite dump begin ------------\n");
    if (!buffer_) {
        return;
        printf("no data.\n");
    }
    auto pkg = std::make_shared<tg::PackageRead>( 
				  buffer_
				, buf_len_ );
    printf("length: %d\n", pkg->GetLength());
    printf("action: %d\n", tg_pkg_ts_action(pkg->GetAction()));
    printf("data length: %d\n", pkg->GetDataLength());
    printf("data -------->>>\n");
    printf("%s\n", pkg->GetDataBuffer());
    printf("--------- PackageWrite dump end ------------\n");
}
#endif
//------------------//
void PackageWrite::SetAction(Package::eAction act) {
    action_ = act;
}

void PackageWrite::SetLocalSocket(SOCKET sock) {
    sock_local_ = sock;
}

void PackageWrite::SetRemoteSocket(SOCKET sock) {
    sock_remote_ = sock;
}

void PackageWrite::SetDataLength(uint16_t len) {
    data_len_ = len;
}

void PackageWrite::SetData(const char* data) {
    data_buf_ = data;
}

}